/*******************************************************************************
 * Copyright (c) 2010 Marcelo Cataldo, Sangeeth Nambiar
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * DepsGraphLayer.java
 * 
 * Implements an abstraction layer for a single single- or bipartite graph.
 * The data represents JUST one relationship among the nodes of the graph.
 * 
 * Contributors:
 *    Marcelo Cataldo  - initial implementation 
 *    Sangeeth Nambiar - initial implementation
 *******************************************************************************/
package edu.cmu.isr.dinvenio.model;

import java.util.*;

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;

import edu.cmu.isr.dinvenio.exceptions.ObjectNotFoundException;

public class DepsGraphLayer {
	
	/*
	 * 
	 */
	private String id;
	private DepsGraphNodeSet nsSource = null;
	private DepsGraphNodeSet nsTarget = null;
	
	private boolean enabled;
	private boolean visibility;

	private String edgeColorProperty;	// index to edge property that determines the color of the edge
	private String edgeColor;			// RBG format embedded in a String in the form RRR,GGG,BBB
	
	private int edgeWeight_max;         // max/min for edge thickness scaling
	public int edgeWeight_min;
	
	private ArrayList<DepsGraphEdge> edges;

	/*
	 * Constructors
	 */
	public DepsGraphLayer(String id, DepsGraphNodeSet s, DepsGraphNodeSet d) 
	{
		this.id = id;
		
		this.nsSource = s;
		if (nsSource == null) { throw new NullPointerException(); }
		this.nsTarget = d;
		if (nsTarget == null) { throw new NullPointerException(); }
		
		this.enabled    = true;
		this.visibility = true;
		
		edges = new ArrayList<DepsGraphEdge>();
		
		edgeWeight_max = 0;
		edgeWeight_min = Integer.MAX_VALUE;
		
		edgeColorProperty = null;		
		// By default the color is black
		edgeColor = "000,000,000";
	}


	/*
	 * ACCESSOR methods
	 */
	public String getID()
	{
		return id;
	}

	public String getSourceNodeSetId() 
	{
		return nsSource.getId();
	}

	public String getTargetNodeSetId() 
	{
		return nsTarget.getId();
	}

	public DepsGraphNode getSourceNodeByName(String nid) {
		return nsSource.getNodeByName(nid);
	}
	
//	public DepsGraphNode getSourceNodeByKey(String nkey) {
//		return nsSource.getNodeByKey(nkey);
//	}
	
	public DepsGraphNode getTargetNodeByName(String nid) {
		return nsTarget.getNodeByName(nid);
	}
	
//	public DepsGraphNode getTargetNodeByKey(String nkey) {
//		return nsTarget.getNodeByKey(nkey);
//	}
	
	public String getPropertyForEdgeColor()
	{
		return edgeColorProperty;
	}
	
	public void setPropertyForEdgeColor(String p)
	{
		edgeColorProperty = p;
	}

	public ArrayList<DepsGraphEdge> getEdges() {
		return edges;
	}

	public void setEdgeColor(String cstr) 
	{
		if (cstr != null && cstr.length() == 11) {
			edgeColor = cstr;
		}
	}

	/*
	 * Methods for ADDING/REMOVING elements
	 */	
	public void addEdge(String source, String target, double weight) throws ObjectNotFoundException
	{
		if (!nsSource.hasNodeByName(source)) {
			throw new ObjectNotFoundException("DepsGraphLayer.addEdge: Invalid source node");
		}
		if (!nsTarget.hasNodeByName(target)) {
			throw new ObjectNotFoundException("DepsGraphLayer.addEdge: Invalid target node");
		}
		edges.add(new DepsGraphEdge(source, target, weight,this.getAWTColor(),this));
		if (weight < edgeWeight_min) { edgeWeight_min = (int)weight; }
		if (weight > edgeWeight_max) { edgeWeight_max = (int)weight; }
	}
	
	/*
	 * Methods for SEARCHING elements
	 */
	public boolean isTechnicalLayer() 
	{
		return (nsSource.isTechnicalNodeSet() && nsTarget.isTechnicalNodeSet());
	}
	
	public boolean isOrganizationalLayer() 
	{
		return (nsSource.isOrganizationalNodeSet() && nsTarget.isOrganizationalNodeSet());
	}
	
	public boolean isBipartiteLayer() 
	{
		return ((nsSource.isTechnicalNodeSet() && nsTarget.isOrganizationalNodeSet()) ||
				(nsTarget.isTechnicalNodeSet() && nsSource.isOrganizationalNodeSet()));
	}
	
	/*
	 * Methods for VISUALIZATION
	 */
	public void enableLayer()
	{
		this.enabled = true;
	}
	
	public void disableLayer()
	{
		this.enabled = false;
	}
	
	public boolean getEnableStatus()
	{
		return this.enabled;
	}

	public void setVisibility(boolean vis) 
	{
		this.visibility = vis;
	}
	public boolean getVisibility()
	{
		return this.visibility;
	}
	
	public java.awt.Color getAWTColor() 
	{
		int red = Integer.parseInt(edgeColor.substring(0,3));
		int green = Integer.parseInt(edgeColor.substring(4,7));
		int blue = Integer.parseInt(edgeColor.substring(8,11));
		return new java.awt.Color( red, green, blue);
	}
	
	public Color getSWTColor(Display display) {
		int red = Integer.parseInt(edgeColor.substring(0,3));
		int green = Integer.parseInt(edgeColor.substring(4,7));
		int blue = Integer.parseInt(edgeColor.substring(8,11));
		Color cl = new Color(display, red, green, blue);
		return cl;
	}

	public void updateNodeDegrees()
	{
		for(int i = 0; i < this.edges.size(); i++) {
			DepsGraphEdge edge = edges.get(i);
			DepsGraphNode source = nsSource.getNodeByName(edge.source);
			DepsGraphNode target = nsTarget.getNodeByName(edge.target);
						
			source.outDegree++;
			source.outWeight += edge.getEdgeWeight();
			
			target.inDegree++;
			target.inWeight += edge.getEdgeWeight();
		}
	}
}
